/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import { useAsyncEffect } from 'ahooks';
import i18n from 'i18next';
import { useMemo, useState } from 'react';

import { BaseCommand, pickedLineData, pickedVertexData } from '@amcax/base';
import { CurvedCmdDialogParams } from '@app-base/types';
import { useTools } from '@app-base/common/hooks/useTools';
import { RJSFSchema } from '@rjsf/utils';
import { PickableCommandForm } from '@app-base/common/components/command-form/pickable';
import {
  NumberInputFormat,
  PickInputRJSFFormat,
} from '@app-base/common/components/command-form/constants';
import { omitBy } from 'lodash';
import { useCommand } from '@app-base/common/hooks/useCommand';
import { getIdOfPickedObj } from '@app-base/common/utils/render';
import { MessageTip } from '@app-base/common/utils/MessageTip';
import { Vector3 } from 'three-legacy';

type Params = {
  mode: string; // "HP/HT/PT", 高度螺距， 高度转数，螺距转数
  height: number;
  pitch: number; // 螺距, 三选二
  turns: number; // 转数, 三选二
  angle: number; // 起始角度
  point?: string; // 起点
  axis?: string; // 轴
  draft?: number; // 可选，拔模角度
  reverse?: boolean; // 可选, 反转方向
  leftup?: boolean; // 可选
};

type FormData = {
  mode: string; // "HP/HT/PT", 高度螺距， 高度转数，螺距转数
  point?: pickedVertexData; // 起点
  height: number;
  pitch: number; // 螺距, 三选二
  turns: number; // 转数, 三选二
  angle: number; // 起始角度

  axis?: pickedLineData; // 轴
  // draft?: number; // 可选，拔模角度
  leftup?: string; // 可选
};

// 螺旋线
function HelixCommand({ title, onClose, props }: CurvedCmdDialogParams) {
  const initData: FormData = {
    mode: 'PT',
    height: 50,
    pitch: 5,
    turns: 10,
    angle: 0,
    axis: null,
  };

  const [formData, setFormData] = useState<FormData>(initData);

  const { picker } = useTools();

  useAsyncEffect(async () => {
    if (props == null) {
      setFormData(initData);
      return;
    }

    const { mode, point, axis, height, pitch, turns, angle, reverse, leftup } =
      props.params as Params;

    await initEditDependency([point, axis]);

    const pointObj = point
      ? (picker.generatePickObjByPickID(point) as pickedVertexData)
      : null;

    if (!pointObj) {
      // 这时是老格式的螺旋线，不再支持编辑。
      MessageTip.warning('当前螺旋线不支持编辑，如需修改请删除后重新创建');
      onClose();
      return;
    }

    const axisObj = axis
      ? (picker.generatePickObjByPickID(axis, {
          showArrow: true,
        }) as pickedLineData)
      : null;
    if (axisObj && reverse) {
      axisObj.assisObj.reverse();
    }

    setFormData({
      mode,
      point: pointObj,
      axis: axisObj,
      height,
      pitch,
      turns,
      angle,
      leftup: leftup ? '1' : '0',
    });
  }, []);

  const isFormDataValid = () => {
    const { point, axis } = formData;

    if (point == null || axis == null) {
      return false;
    }

    if (formData.mode === 'HP' || formData.mode === 'PT') {
      if (formData.pitch <= 0) {
        return false;
      }
    }
    if (formData.mode === 'HP' || formData.mode === 'HT') {
      if (formData.height <= 0) {
        return false;
      }
    }
    if (formData.mode === 'HT' || formData.mode === 'PT') {
      if (formData.turns <= 0) {
        return false;
      }
    }

    return true;
  };

  useAsyncEffect(async () => {
    if (!isFormDataValid()) {
      clear();
      return;
    }

    await execute(true);
  }, [formData]);

  const checkAndFinishDraw = async () => {
    if (!isFormDataValid()) {
      return;
    }

    await execute(false);

    onClose();
  };

  const { initEditDependency, initingEdit, clear, confirmCommand, isLoading } =
    useCommand('cmd-helix', {
      commandName: 'CreateCurve',
      editDxid: props?.shape,
      onClose,
      finishDraw: checkAndFinishDraw,
    });

  const execute = (preview: boolean) => {
    return confirmCommand(
      {
        type: 'Helix',
        a: {
          mode: formData.mode,
          point: getIdOfPickedObj(formData.point),
          height: formData.height,
          pitch: formData.pitch,
          turns: formData.turns,
          angle: formData.angle,
          axis: getIdOfPickedObj(formData.axis),
          reverse: formData.axis?.assisObj.isReversed || false,
          leftup: formData.leftup?.toString() === '1' || false,
        },
      },
      preview,
    );
  };

  const isPointOnLine = (point: pickedVertexData, line: pickedLineData) => {
    const pointVector = new Vector3(...point.assisObj.positions);
    const lineVectos = line.edgeData;
    for (let i = 0; i < lineVectos.length; i++) {
      if (pointVector.distanceTo(lineVectos[i]) < 1e-6) {
        return true;
      }
    }

    return false;
  };

  const schema: RJSFSchema = useMemo(() => {
    const properties = omitBy(
      {
        pitch:
          formData.mode === 'HP' || formData.mode === 'PT'
            ? {
                type: 'number',
                title: '螺距',
                minimum: 0,
                format: NumberInputFormat.Length,
              }
            : null,
        height:
          formData.mode === 'HP' || formData.mode === 'HT'
            ? {
                type: 'number',
                title: '高度',
                default: 0,
                minimum: 0,
                format: NumberInputFormat.Length,
              }
            : null,
        turns:
          formData.mode === 'HT' || formData.mode === 'PT'
            ? {
                type: 'number',
                title: '转数',
                default: 0,
                minimum: 0,
                format: NumberInputFormat.Real,
              }
            : null,

        leftup: {
          // 需要实现 下拉菜单的方式来 切换
          type: 'string',
          title: '旋向',
          oneOf: [
            {
              type: 'string',
              title: '逆时针',
              const: '0',
            },
            {
              type: 'string',
              title: '顺时针',
              const: '1',
            },
          ],
          default: '1',
        },
        angle: {
          type: 'number',
          title: '起始角度',
          format: NumberInputFormat.Angle,
        },
        // 拔模 相关配置 目前先不做，后续再开要不要补全
        // draft: {
        //   type: 'number',
        //   title: '拔模角度',
        //   format: NumberInputFormat.Angle,
        // },
      },
      (val) => val == null,
    );

    return {
      type: 'object',
      properties: {
        mode: {
          title: '螺旋类型',
          type: 'string',
          oneOf: [
            {
              type: 'string',
              title: '螺距和转数',
              const: 'PT',
            },
            {
              type: 'string',
              title: '高度和螺距',
              const: 'HP',
            },
            {
              type: 'string',
              title: '高度和转数',
              const: 'HT',
            },
          ],
          default: 'PT',
        },
        point: {
          title: '起点',
          type: 'string',
          format: PickInputRJSFFormat.PickVertex,
        },
        axis: {
          title: '螺旋轴',
          type: 'string',
          format: PickInputRJSFFormat.PickLine,
        },
        ...properties,
      },
    } as RJSFSchema;
  }, [formData.mode]);

  return (
    <PickableCommandForm
      disabled={initingEdit}
      onClose={onClose}
      submitLoading={isLoading}
      title={title}
      schema={schema}
      formData={formData}
      onChange={(v) => {
        if (v.point != null && v.axis != null) {
          if (isPointOnLine(v.point, v.axis)) {
            if (formData.point == null) {
              v.point = null; // 如果是新选择的点，则不允许在轴线上
              MessageTip.warning(
                '起点位于螺旋轴上。请给出一个不在螺旋轴上的起点',
              );
            } else if (formData.axis == null) {
              v.axis = null; // 如果是新选择的轴，则不允许在点上
              MessageTip.warning('起点位于螺旋轴上。无法选择该螺旋轴');
            }
          }
        }
        setFormData(v);
      }}
      extraUiSchema={{
        point: {
          'ui:placeholder': '请输入点',
          'ui:autofocus': true,
        },
        axis: {
          'ui:placeholder': '请输入直线、轴线',
          'ui:options': {
            showArrow: true,
            curveReversable: true,
          },
        },
      }}
      submitText='完成'
      onSubmit={checkAndFinishDraw}
      isFormDataValid={isFormDataValid()}
    />
  );
}

export const cmdHelix: BaseCommand = {
  id: 'CmdHelix',
  label: 'command.helix',
  icon: 'commands/feature/helix',
  create: (label, onClose, props) => (
    <HelixCommand
      title={i18n.t(label)}
      onClose={onClose}
      props={props}
    />
  ),
};
